#ifndef TreeView_First
#define TreeView_First
#ifdef __GNUG__
#pragma interface
#endif

#include "CompVObject.h"
#include "DialogView.h"

class TreeNode;

enum TreeLayout {
	eTLIndented,
	eTLTopDown,
	eTLLeftRight,
	eTLNew
};

enum TreeConnection {
	eTCNone,
	eTCDiagonal,
	eTCPerpendicular,
	eTCDiagonal2
};

//---- TreeView ----------------------------------------------------------------

class TreeView: public DialogView {
public:
	MetaDef(TreeView);

	TreeView(EvtHandler*, TreeLayout lt= eTLLeftRight,
									TreeConnection ct= eTCPerpendicular);

	VObject *DoCreateDialog();
	void SetTree(TreeNode*, bool freeold= TRUE);
	void SetExtent(Point e);
	void Promote(TreeNode*);
	virtual void Collapse(TreeNode*);
	virtual void OpenTreeNode(TreeNode*, bool);
	VObject *FindNode(VObject *);
	TreeNode *GetTree()
		{ return tree; }

	//---- layout
	void SetLayout(TreeLayout);
	TreeLayout GetLayout()
		{ return layout; }
	void SetConnType(TreeConnection);

	//---- event handling
	Command *DispatchEvents(Point lp, Token &t, Clipper*);
	virtual Command *NodeSelected(VObject*, int cl);
	virtual Command *GetNodeSelector(TreeNode *tn, int cl);

	//---- input/output
	OStream& PrintOn(OStream&);
	IStream& ReadFrom(IStream&);
	void Export(OStream&);

	//---- hooks for BuildTree
	void InstallTree(Object *root);
	VObject *BuildTree(Object *root);
	virtual VObject *NodeAsVObject(Object *);
	virtual Iterator *MakeChildrenIter(Object *);
	virtual TreeNode *MakeTreeNode(int id, SeqCollection *items);

	//---- selection
	virtual void SetSelection(VObject *gp);
	Command *DoMenuCommand(int cmd);
	bool HasSelection();
	VObject *GetSelection()
		{ return selection; }

public:
	Point gap;
	TreeLayout layout;
	TreeConnection connType;
	TreeNode *tree, *oldtree;
	VObject *selection;
};

struct line {
	Point d;
	line *link;
		
	line(Point dd, line *l)
		{ d= dd; link= l; }
	void draw(Point pos);
};

struct polygon {
	struct {
		line *head, *tail;
	} lower, upper;

	polygon()
		{ lower.head= lower.tail= upper.head= upper.tail= 0; }
	int merge(polygon *c2);
	void draw(int h, Point pos);
	Point bbox(int h);
	int loffset();
};

//---- TreeNode ------------------------------------------------------------------

enum TreeNodeFlags {
	eTreeNodeCollapsed  =   BIT(eCompVObjLast+1),
	eTreeNodeDefault    =   eCompVObjDefault,
	eTreeNodeLast       =   eCompVObjLast+1
};

class TreeNode: public CompositeVObject {
public:
	Point offset;
	polygon contour;
public:
	MetaDef(TreeNode);

	TreeNode(int id= cIdNone, SeqCollection *cp= 0);
	TreeNode(int id, ...);
	TreeNode(int id, va_list ap);

	TreeView *GetTreeView();
	bool Collapsed()
		{ return TestFlag(eTreeNodeCollapsed); }
	void Open(bool);
	void Collapse();
	TreeConnection ConnType()
		{ return GetTreeView()->connType; }
	TreeLayout Layout()
		{ return GetTreeView()->layout; }
	Point Gap()
		{ return GetTreeView()->gap; }
	VObject *Detect(BoolFun f, void *arg);
	VObject *FindExpandedItem(VObject*);

	//---- layout
	void SetOrigin(Point at);
	void SetExtent(Point e);
	Metric GetMinSize();

	int join();
	int width()
		{ return At(0)->contentRect.extent.x; }
	int height()
		{ return At(0)->contentRect.extent.y; }

	//---- drawing
	void Draw(Rectangle);
	void DrawConnections();
	void Outline2(Point, Point);
	void Highlight(HighlightState hst);
	GrCursor GetCursor(Point lp);

	//---- event handling
	Command *DispatchEvents(Point lp, Token &t, Clipper *cl);
	Command *DoMiddleButtonDownCommand(Point lp, Token t, int cl);
	Command *DoLeftButtonDownCommand(Point lp, Token t, int cl);

	//---- input/output
	void Export(OStream &s, int level);
};

//---- TreeNodeSelector -------------------------------------------------------------

class TreeNodeSelector: public Command {
	TreeNode *item;
	bool inside, lastinside;
	int clicks;
public:
	TreeNodeSelector(TreeNode *s, int cl);
	void TrackFeedback(Point, Point, bool);
	Command *TrackMouse(TrackPhase, Point, Point, Point);
};

#endif

